package com.hyt.it.ogt.kq.service.govData.service.kz.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.cj.model.entity.ProjectCollectInfo;
import com.hyt.it.ogt.cj.service.IProjectCollectInfoService;
import com.hyt.it.ogt.kq.common.config.ConfigManager;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.utils.CacheKeyManager;
import com.hyt.it.ogt.kq.common.govData.enums.kw.CandidateStatusCode;
import com.hyt.it.ogt.kq.common.govData.enums.kw.EmailOrMessageSendStatusCode;
import com.hyt.it.ogt.kq.common.govData.enums.kw.MessageSendStatusCode;
import com.hyt.it.ogt.kq.service.gov.feign.ks.model.PushTimeRoomCandidateParam;
import com.hyt.it.ogt.kq.service.gov.feign.ks.model.PushTimeRoomCandidateVO;
import com.hyt.it.ogt.kq.service.govData.mapper.kz.ExamCandidateMapper;
import com.hyt.it.ogt.kq.service.govData.model.entity.kz.*;
import com.hyt.it.ogt.kq.service.govData.service.kz.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author wuyingge
 * @version 1.0.0
 * @ClassName IExamCandidateServiceImpl.java
 * @Description 
 * @createTime 2022年09月05日 16:48:00
 */
@Service
@Slf4j
public class ExamCandidateServiceImpl extends BaseServiceImpl<ExamCandidateMapper, ExamCandidate> implements IExamCandidateService {

    @Resource
    private IProjectCollectInfoService iProjectCollectInfoService;
    @Resource
    private IExamCandidateInfoService iExamCandidateInfoService;
    @Resource
    private IExamCandidateExtService iExamCandidateExtService;
    @Resource
    private IExamService iExamService;
    @Resource
    private IExamPaperService iExamPaperService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private ConfigManager configManager;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void pushTimeRoomCandidate(PushTimeRoomCandidateParam pushTimeRoomCandidateParam) {
        try {
            String uuid = UUIDUtils.newSortUUID();
            List<PushTimeRoomCandidateVO> pushTimeRoomCandidateVOs = pushTimeRoomCandidateParam.getPushTimeRoomCandidateVOS();
            List<ExamCandidate> examCandidateList = new ArrayList<ExamCandidate>();
            List<ExamCandidateExt> examCandidateExtList = new ArrayList<ExamCandidateExt>();
            List<ExamCandidateInfo> examCandidateInfoList = new ArrayList<ExamCandidateInfo>();

            long e1 = System.currentTimeMillis();
            for (PushTimeRoomCandidateVO pushTimeRoomCandidate : pushTimeRoomCandidateVOs) {
                String examId = pushTimeRoomCandidate.getTimeId();
                //考生表
                ExamCandidate examCandidate = this.getAddExamCandidate(examId, pushTimeRoomCandidate.getAdmissionNum(), "");
                String examCandidateId = UUIDUtils.newSortUUID();
                examCandidate.setId(examCandidateId);
                if(Objects.nonNull(pushTimeRoomCandidate.getBmSubjectId())){
                    examCandidate.setGovSubjectId(pushTimeRoomCandidate.getBmSubjectId());
                } else {
                    examCandidate.setGovSubjectId(pushTimeRoomCandidate.getSubjectId());
                }
                examCandidate.setGovSubjectName(pushTimeRoomCandidate.getSubjectName());
                examCandidate.setGovCandidateId(pushTimeRoomCandidate.getCandidateId());
                examCandidate.setRoomId(pushTimeRoomCandidate.getRoomId());
                examCandidate.setRoomCode(pushTimeRoomCandidate.getRoomCode());
                examCandidate.setManualReview(0);
                examCandidate.setName(pushTimeRoomCandidate.getName());
                examCandidate.setPhone(pushTimeRoomCandidate.getPhone());
                examCandidate.setCardType(String.valueOf(pushTimeRoomCandidate.getIdType()));
                examCandidate.setCardNumber(pushTimeRoomCandidate.getIdNumber());
                examCandidateList.add(examCandidate);
                //考生拓展表
                ExamCandidateExt examCandidateExt = new ExamCandidateExt();
                examCandidateExt.setId(UUIDUtils.newSortUUID());
                examCandidateExt.setExamId(examId);
                examCandidateExt.setCandidateId(examCandidateId);
                examCandidateExt.setRoomId(pushTimeRoomCandidate.getRoomId());
                examCandidateExt.setRoomName(pushTimeRoomCandidate.getRoomName());
                examCandidateExt.setDelFlag(Boolean.FALSE);
                examCandidateExtList.add(examCandidateExt);

                List<ProjectCollectInfo> projectCollectInfos = getProjectCollectInfos(examId);
                //考生信息表
                //获取考生信息采集
                for (ProjectCollectInfo projectCollectInfo : projectCollectInfos) {
                    ExamCandidateInfo examCandidateInfo = new ExamCandidateInfo();
                    examCandidateInfo.setId(UUIDUtils.newSortUUID());
                    examCandidateInfo.setConfigCode(projectCollectInfo.getId());
                    examCandidateInfo.setExamCandidateId(examCandidateId);
                    examCandidateInfo.setExamId(examId);
                    if (CollectInfoComponentNameCode.CANDIDATE_CONFIG_NAME.getCode()
                            .equals(projectCollectInfo.getComponentName())) {
                        examCandidateInfo.setConfigValue(pushTimeRoomCandidate.getName());
                    } else if (CollectInfoComponentNameCode.CANDIDATE_CONFIG_SEX.getCode()
                            .equals(projectCollectInfo.getComponentName())) {
                        examCandidateInfo.setConfigValue(String.valueOf(pushTimeRoomCandidate.getSex()));
                    } else if (CollectInfoComponentNameCode.CERTIFICATE_TYPE.getCode()
                            .equals(projectCollectInfo.getComponentName())) {
                        examCandidateInfo.setConfigValue(String.valueOf(pushTimeRoomCandidate.getIdType()));
                    } else if (CollectInfoComponentNameCode.CANDIDATE_CONFIG_IDCARD.getCode()
                            .equals(projectCollectInfo.getComponentName())) {
                        examCandidateInfo.setConfigValue(pushTimeRoomCandidate.getIdNumber());
                    } else if (CollectInfoComponentNameCode.BIRTHDAY.getCode()
                            .equals(projectCollectInfo.getComponentName())) {
                        examCandidateInfo.setConfigValue(pushTimeRoomCandidate.getBirthday());
                    } else if (CollectInfoComponentNameCode.CANDIDATE_CONFIG_CERTIFICATE_PHOTO.getCode()
                            .equals(projectCollectInfo.getComponentName())) {
                        examCandidateInfo.setConfigValue(pushTimeRoomCandidate.getPhotoPath());
                    } else if (CollectInfoComponentNameCode.CANDIDATE_CONFIG_PHONE.getCode()
                            .equals(projectCollectInfo.getComponentName())) {
                        examCandidateInfo.setConfigValue(pushTimeRoomCandidate.getPhone());
                    } else if (CollectInfoComponentNameCode.CANDIDATE_CONFIG_EMAIL.getCode()
                            .equals(projectCollectInfo.getComponentName())) {
                        examCandidateInfo.setConfigValue(pushTimeRoomCandidate.getEmail());
                    }
                    examCandidateInfo.setDelFlag(Boolean.FALSE);
                    examCandidateInfoList.add(examCandidateInfo);
                }
            }
            long e2 = System.currentTimeMillis();
            log.info("# pushTimeRoomCandidate第一步耗时：{}，{}", uuid, e2 - e1);
            if (CollUtil.isNotEmpty(examCandidateList)) {
                List<List<ExamCandidateInfo>> partitionExamCandidateInfoList = Lists.partition(examCandidateInfoList, configManager.getBatchSaveSize());
                // 如果数据量比较大的话，分组修改1000一组
                if (CollectionUtils.isNotEmpty(partitionExamCandidateInfoList)) {
                    for (List<ExamCandidateInfo> examCandidateInfos : partitionExamCandidateInfoList) {
                    	iExamCandidateInfoService.batchSave(examCandidateInfos);
                    }
                }



                long e3 = System.currentTimeMillis();
                log.info("# pushTimeRoomCandidate第二步耗时：{}，{}", uuid, e3 - e2);
                List<List<ExamCandidateExt>> partitionExamCandidateExtList = Lists.partition(examCandidateExtList, configManager.getBatchSaveSize());
                // 如果数据量比较大的话，分组修改1000一组
                if (CollectionUtils.isNotEmpty(partitionExamCandidateExtList)) {
                    for (List<ExamCandidateExt> examCandidateInfos : partitionExamCandidateExtList) {
                    	iExamCandidateExtService.batchSave(examCandidateInfos);
                    }
                }



                long e4 = System.currentTimeMillis();
                log.info("# pushTimeRoomCandidate第三步耗时：{}，{}", uuid, e4 - e3);
                List<List<ExamCandidate>> partitionExamCandidateList = Lists.partition(examCandidateList, configManager.getBatchSaveSize());
                // 如果数据量比较大的话，分组修改1000一组
                if (CollectionUtils.isNotEmpty(partitionExamCandidateList)) {
                    for (List<ExamCandidate> examCandidates : partitionExamCandidateList) {
                    	this.batchSave(examCandidates);
                    }
                }

                long e5 = System.currentTimeMillis();
                log.info("# pushTimeRoomCandidate第四步耗时：{}，{}", uuid, e5 - e4);
            }
            log.info("推送考生编排数据入库kw库完成，完成考生个数为:【{}】",pushTimeRoomCandidateParam.getPushTimeRoomCandidateVOS().size());
        } catch (Exception e){
			log.error("推送考生编排数据入库kw库，推送参数为:【{}】", pushTimeRoomCandidateParam, e);
            throw new KqException(ResponseCode.PUSH_TIME_ROOM_CANDIDATE_ERROR.getCode(),
                    ResponseCode.PUSH_TIME_ROOM_CANDIDATE_ERROR.getMsg());
        } finally {
            String progressKey = CacheKeyManager.getDataLockProgressKey(pushTimeRoomCandidateParam.getTaskId());
            redisTemplate.opsForValue().increment(progressKey, pushTimeRoomCandidateParam.getPushTimeRoomCandidateVOS().size());
        }
    }

    /**
     * 批量保存
     * @return
     */
    private Boolean batchSave(List<ExamCandidate> records){
        return baseMapper.batchSave(records) > 0;
    }


    private ExamCandidate getAddExamCandidate(String examId, String admissionNumber, String officeId) {
        ExamCandidate examCandidate = new ExamCandidate();
        examCandidate.setExamId(examId);
        examCandidate.setSelfDefineAdmission(false);
        examCandidate.setAdmissionNumber(admissionNumber);
        examCandidate.setSendEmail(EmailOrMessageSendStatusCode.NOT_SEND.getCode());
        examCandidate.setSendMessage(MessageSendStatusCode.NOT_SEND.getCode());
        examCandidate.setForbidEndExam(false);
        examCandidate.setJudgeScoreState(false);
        examCandidate.setState(0);
        examCandidate.setOfficeId(officeId);
        examCandidate.setSubjectiveScore(new BigDecimal("0"));
        examCandidate.setObjectiveScore(new BigDecimal("0"));
        examCandidate.setDelFlag(false);
        examCandidate.setAcquired(0);
        return examCandidate;
    }

    @Override
    public Integer deleteTimeRoomCandidate(String taskId) {
        List<Exam> examList = iExamService.getByTaskId(taskId);
        if(CollUtil.isEmpty(examList)) {
        	return 0;
        }
        //发布批次数量
        Long publishCount = examList.stream().filter(e -> e.getPublishExam()).count();
        List<String> examIds = examList.stream().map(e -> e.getId()).collect(Collectors.toList());

        //不是未登录考生
        int candidateCount = this.countLoginCandidates(examIds);

        //导入试卷数
        int paperCount = iExamPaperService.countByExamIds(examIds);
        if (publishCount.intValue() > 0 || candidateCount > 0 || paperCount > 0) {
            return 1;
        }
        //删除考生拓展表
        iExamCandidateExtService.removeByExamIds(examIds);
        //删除考生信息表
        iExamCandidateInfoService.removeByExamIds(examIds);
        //删除考生表
        this.removeByExamIds(examIds);
        return 0;
    }

    @DS("kz")
    private Integer countLoginCandidates(List<String> examIds){
        LambdaQueryWrapper<ExamCandidate> queryCandidateWrapper = Wrappers.lambdaQuery();
        queryCandidateWrapper.in(ExamCandidate::getExamId, examIds)
                .and(i -> i.ne(ExamCandidate::getState, CandidateStatusCode.UN_TEST.getCode()));
        return this.count(queryCandidateWrapper);
    }

    /**
     * 通过考试id来删除考生
     * @return
     */
    @DS("kz")
    private Boolean removeByExamIds(List<String> examIds){
        LambdaQueryWrapper<ExamCandidate> queryAllCandidateWrapper = Wrappers.lambdaQuery();
        queryAllCandidateWrapper.in(ExamCandidate::getExamId, examIds);
        return super.remove(queryAllCandidateWrapper);
    }

    /**
     * 查询考生信息结构-报名任务下都一样
     * @param examId
     * @return
     */
    @DS("kz")
    private List<ProjectCollectInfo> getProjectCollectInfos(String examId) {

        QueryWrapper<ProjectCollectInfo> query = Wrappers.query();
        query.lambda().eq(ProjectCollectInfo::getProjectId, examId)
                .eq(ProjectCollectInfo::getDelFlag, false);
        List<ProjectCollectInfo> projectCollectInfos = iProjectCollectInfoService.list(query);

        return projectCollectInfos;
    }
}
